/*/////////////////////////////////////////////////////////////////////////////////////////////////
    Groovy Closure Sematics

    1.  They have one implicit method (which is never specified in a closure definition) called doCall()
    2. A closure may be invoked via the call() method
*//////////////////////////////////////////////////////////////////////////////////////////////////

def closure = { println it }
closure.call(5)

//  or with a special syntax of an unnamed () invocation.

closure(22)

//   Either invocation will be translated by Groovy into a call to the Closure's doCall() method.

/*/////////////////////////////////////////////////////////////////////////////////////////////////
    3. Closures may have 1...N arguments(comma seperated), which may be statically typed or untyped.
    The first parameter is available via an implicit untyped argument named 'it'
    if no explicit arguments are named.
*//////////////////////////////////////////////////////////////////////////////////////////////////

def oneImplicitArg = { it * 2 }
assert oneImplicitArg('A') == 'AA'

// If the caller does not specify any arguments, the first parameter (and, by extension, 'it') will be null.

def emptyArg = { x -> return x }
assert emptyArg()  == null

// Implementing variable args;
def varArgs = {x, Object[] args->
    return "$x $args"
}
assert varArgs('one', 'two', 'three') == 'one {"two", "three"}'
assert  varArgs('one') == 'one {}'

/*/////////////////////////////////////////////////////////////////////////////////////////////////
    4. The developer does not have to use 'it' for the first parameter.
     If they wish to use a different name, they may specify it in the parameter list.
*//////////////////////////////////////////////////////////////////////////////////////////////////

def oneExplicitArg = { x -> x * 2 }
assert oneExplicitArg('Z') == 'ZZ'

/*//////////////////////////////////////////////////////////////////////////////////////////////////
    5. Closures always return a value. This may occur via either an explicit return statement,
*//////////////////////////////////////////////////////////////////////////////////////////////////
Closure explicitReturn = {
    return it
}
assert explicitReturn(5) == 5

// or as the value of the last statement in the closure body (e.g. an explicit return statement is optional).
Closure implicitReturn = {
    it * 2
}
assert implicitReturn(5) == 10

/*/////////////////////////////////////////////////////////////////////////////////////////////////
    6. A closure may reference any variables defined within its enclosing lexical scope.
    Any such variable is said to be bound to the closure

    7. Any variables bound to a closure are available to the closure even when the
    closure is returned outside of the enclosing scope.

    Birth Context: The closure constructs a list of elements from what it rememebers
    from it's birth, that are only bound to it when the closure is called.
*//////////////////////////////////////////////////////////////////////////////////////////////////
class Mother {
    int field = 1
    int foo(){
        2
    }

    Closure birth(param){   // creates and returns the closure
        def local = 3
        def closr = { caller ->
            [this, field, foo(), local, param, caller, owner, delegate]
        }
        return closr
    }
}

Mother julia = new Mother()
Closure c = julia.birth(4)  //  Just adding a value to the birth context
context = c.call(this) // This is the point at whcih all variables are bound

assert context[0].class.name == 'Mother'    //this: the enclosing class where the Closure is defined
assert context[1..4] == [1, 2, 3, 4]              //[field, foo(), local, param]
assert context[5].class.name == 'ClosureScript' //caller
assert context[6].class.name == 'Mother'    //owner: the enclosing object
assert context [7].class.name == 'Mother' //delegate: defalt same as owner

/*/////////////////////////////////////////////////////////////////////////////////////////////////
    8. Closures are first class objects in Groovy, and are always derived from the class Closure.
     Code which uses closures may reference them via untyped variables or variables typed as Closure.
*//////////////////////////////////////////////////////////////////////////////////////////////////

def untyped = { println it }
Closure typed = {println it}
assert untyped instanceof Closure
assert untyped instanceof Object
assert typed instanceof Closure
assert typed instanceof Object

/*/////////////////////////////////////////////////////////////////////////////////////////////////
    9. The body of a closure is not executed until it is explicitly invoked
    e.g. a closure is not invoked at its definition time (Lazy Evaluation)
*//////////////////////////////////////////////////////////////////////////////////////////////////
def it = 9
Closure x = { println it }  // will not print 9
x(15)                               // prints 15

/*/////////////////////////////////////////////////////////////////////////////////////////////////
    10. A closure may be curried so that  a copy of the closure is made with
    one or more of its parameters fixed to a constant value
*//////////////////////////////////////////////////////////////////////////////////////////////////

/*////////////////////////
    Simple Example
*////////////////////////
def multipler = { a, b -> a*b}
def doubler = multipler.curry(2)
def trippler = multipler.curry (3)
def quad = multipler.curry(4)

assert doubler(5) == 10
assert trippler(5) == 15
assert quad(5) == 20

/*//////////////////////////////////////
    Complex(?) Example
    Closures are typed for clarity
*//////////////////////////////////////

def doCalc  = { Closure bonusPct,  baseAmt->
    baseAmt * bonusPct(baseAmt)
}

def config = { Closure equation, Closure append, baseAmt ->
    append equation (baseAmt)
}

def regularBonus = { multiplyer=1, baseAmt ->
    switch(baseAmt){
        case 50..100 : return 0.10 * multiplyer
        case {it > 100} : return 0.20 * multiplyer
        default : return 0
     }
}

def appendConsole = { output -> println "Your Bonus is: \$${output}" }

def regular = doCalc.curry(regularBonus)
def calculateBonus = config.curry(regular, appendConsole)

calculateBonus(100)
calculateBonus(49)
calculateBonus(200)

def managemnet = doCalc.curry( regularBonus.curry(2) )
def managementBonus = config.curry ( managemnet, appendConsole )

managementBonus(100)

/*//////////////////////////////////////////////////////////////////////////////////
 Scopeing example
 Accumulator
*////////////////////////////////////////////////////////////////////////////////////

def foo(n){
    return { i -> n += i }
}

def accu = foo(1)

assert accu(2) == 3
assert accu(1) == 4     // the value of variable n is in scope, and carries accross calls
assert accu(3) == 7

/*//////////////////////////////////////////////////////////////////////////////////////////////
References:
http://groovy.codehaus.org/Closures
http://groovy.codehaus.org/Closures+-+Formal+Definition
http://groovy.codehaus.org/Closures+-+Informal+Guide
http://www-128.ibm.com/developerworks/library/j-pg08235/
Groovy In Action, Koning (et al) Manning Publication, 2007
*/////////////////////////////////////////////////////////////////////////////////////////////////